﻿var Ajax = window.Ajax || (function () {
	'user strict';
	var ajax = {
		config: {
			url: '',
			type: 'get',
			data: {},
			cache: false,
			async: true,
			done: function () { },
			fail: function () { },
			always: function () { },
			contentType: 'application/x-www-form-urlencoded',
			headers: {},
			dataType: '',
			json: false,
			context: {}
		},
		request: function (ops, done, fail, always) {
			request(ops, done, fail, always);
		},
		get: function (ops, done, fail, always) {
			request(ops, done, fail, always, 'get');
		},
		post: function (ops, done, fail, always) {
			request(ops, done, fail, always, 'post');
		},
		getJSON: function (ops, done, fail, always) {
			request(ops, done, fail, always, 'json');
		},
		getScript: function (ops, done, fail, always) {
			request(ops, done, fail, always, 'script');
		},
		getScripts: function (ops, done, fail, always) {
			getScripts(ops, done, fail, always);
		}
	};

	function getOptions(ops, done, fail, always) {
		if (typeof ops === 'string') {
			ops = {
				url: ops
			};

			typeof done === 'function' && (ops.done = done);
			typeof fail === 'function' && (ops.fail = fail);
			typeof always === 'function' && (ops.done = always);
		}

		for (var prop in ajax.config) {
			if (typeof ops[prop] === 'undefined') {
				ops[prop] = ajax.config[prop];
			}
		}

		return ops;
	}

	function getParamsString(data, url) {
		var arr = [],
			str;
		for (var name in data) {
			arr.push(name + '=' + encodeURIComponent(data[name]));
		}
		str = arr.join('&');
		if (str !== '') {
			return url ? (url.indexOf('?') < 0 ? '?' + str : '&' + str) : str;
		}
		return '';
	}

	function request(ops, done, fail, always, action) {
		var options = getOptions(ops, done, fail, always);

		options.type = action === 'post' ? 'post' : 'get';

		if (!options.cache && action !== 'post') {
			options.data._ = new Date().getTime();
			options.headers['Cache-Control'] = 'no-cache';
		}

		if (action === 'script') {
			options.complite = function (result, xhr) {
				var script = document.createElement('script'), head = document.getElementsByTagName('head')[0];
				script.text = result;
				head.appendChild(script);
				head.removeChild(script);
				options.done.call(options.context);
			};
		} else if (action === 'json') {
			options.complite = function (result, xhr) {
				options.done.call(options.context, JSON.parse(result), xhr);
			};
		} else {
			options.complite = function (result, xhr) {
				options.done.call(options.context, result, xhr);
			};
		}

		(function (settings) {
			var self = this;

			if (window.ActiveXObject) {
				this.xhr = new ActiveXObject('Microsoft.XMLHTTP');
			} else if (window.XMLHttpRequest) {
				this.xhr = new XMLHttpRequest();
			} else {
				return;
			}

			this.xhr.onreadystatechange = function () {
				if (self.xhr.readyState === 4 && self.xhr.status === 200) {
					var result = self.xhr.responseText;
					if (settings.json === true) {
						result = JSON.parse(result);
					}

					settings.complite(result, self.xhr);
					settings.always.call(settings.context, self.xhr);
				} else if (self.xhr.readyState === 4) {
					settings.fail.call(settings.context, self.xhr);
					settings.always.call(settings.context, self.xhr);
				}
			};

			if (settings.type.toLocaleLowerCase() === 'get') {
				this.xhr.open('GET', settings.url + getParamsString(settings.data, settings.url), settings.async);
				this.xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
			} else {
				this.xhr.open('POST', settings.url, settings.async);
				this.xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
				this.xhr.setRequestHeader('Content-type', settings.contentType);
			}

			for (var name in settings.headers) {
				this.xhr.setRequestHeader(name, settings.headers[name]);
			}

			if (settings.type.toLocaleLowerCase() === 'get') {
				this.xhr.send();
			} else {
				if (settings.dataType === 'json') {
					typeof settings.data === 'string' ? this.xhr.send(settings.data) : this.xhr.send(JSON.stringify(settings.data));
				} else {
					this.xhr.send(getParamsString(settings.data));
				}
			}
		}).call({}, options);
	}

	function getScripts(ops, done, fail, always) {
		if (Object.prototype.toString.call(ops) === '[object Array]') {
			ops = {
				urls: ops
			};
		}

		done = done || ops.done;
		fail = fail || ops.fail;
		always = always || ops.always;

		ops.type = 'get';
		ops.done = localDone;
		ops.fail = localFail;

		var options = getOptions(ops),
			i = options.urls.length,
			n = 0,
			error = false;

		while (i--) {
			options.url = options.urls[i];
			ajax.getScript(options);
		}

		function localDone(response, xhr) {
			n++;
			if (n < options.urls.length) return;

			error && fail && fail.call(options.context);

			done && done.call(options.context);
			always && always.call(options.context);
		}

		function localFail(xhr) {
			error = true;
		}
	}

	return ajax;
})();